package mju.cxf.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.swagger.models.auth.In;
import mju.cxf.context.BaseContext;
import mju.cxf.dto.UserDTO;
import mju.cxf.dto.UserLoginDTO;
import mju.cxf.entity.Integral;
import mju.cxf.entity.User;
import mju.cxf.constant.MessageConstant;
import mju.cxf.enumeration.InitialType;
import mju.cxf.exception.BaseException;
import mju.cxf.exception.BindEmailException;
import mju.cxf.exception.CaptchaException;
import mju.cxf.exception.LoginFailedException;
import mju.cxf.mapper.UserMapper;
import mju.cxf.properties.WeChatProperties;
import mju.cxf.service.IntegralService;
import mju.cxf.service.UserService;
import mju.cxf.utils.HttpClientUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 用户相关业务
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    private final RedisTemplate<String, Object> redisTemplate;
    private final UserMapper userMapper;
    private final IntegralService integralService;
    private final WeChatProperties weChatProperties;
    private static final Integer INITIAL_CREDITS = 20;//初始积分
    private static final String LOCK_PREFIX = "lock:user:";
    private static final long LOCK_EXPIRE_TIME = 5; // 锁过期时间，单位为秒

    @Autowired
    public UserServiceImpl(RedisTemplate<String, Object> redisTemplate, UserMapper userMapper, IntegralService integralService, WeChatProperties weChatProperties) {
        this.redisTemplate = redisTemplate;
        this.userMapper = userMapper;
        this.integralService = integralService;
        this.weChatProperties = weChatProperties;
    }

    //微信登陆接口地址
    private static final String WX_LOGIN = "https://api.weixin.qq.com/sns/jscode2session";

    /**
     * 微信用户登陆
     *
     * @param userLoginDTO 微信登陆数据
     * @return user 返回用户信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public User wxLogin(UserLoginDTO userLoginDTO) {
        String openid = getOpenid(userLoginDTO);
        //判断openId是否为空
        if (openid == null) {
            throw new LoginFailedException(MessageConstant.LOGIN_FAILED);
        }
        User userByOpenId = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getOpenId, openid));
        //判断是否为新用户 新用户自动注册
        if (userByOpenId != null) {
            return userByOpenId;
        } else {
            User userCreate = userLoginDTO.getUserInfo();
            userCreate.setOpenId(openid);
            userCreate.setCreateTime(LocalDateTime.now());
            userCreate.setCredit(100);
            userMapper.insert(userCreate);
            System.out.println(userCreate);
            return userCreate;
        }
    }

    /**
     * 获得openId
     *
     * @param userLoginDTO 给微信code
     * @return openid 返回openid
     */
    private String getOpenid(UserLoginDTO userLoginDTO) {
        Map<String, String> map = new HashMap<>();
        map.put("appid", weChatProperties.getAppid());
        map.put("secret", weChatProperties.getSecret());
        map.put("js_code", userLoginDTO.getCode());
        map.put("gran_type", "authorization_code");
        //调用微信登陆接口 获取openId
        String s = HttpClientUtil.doGet(WX_LOGIN, map);
        JSONObject jsonObject = JSON.parseObject(s);
        return jsonObject.getString("openid");
    }

    /**
     * 用户邮箱绑定模块
     *
     * @param userLoginDto
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void bind(UserLoginDTO userLoginDto) {
        String email = userLoginDto.getEmail();
        if (email == null || userLoginDto.getCaptcha() == null) {
            throw new BindEmailException(MessageConstant.BIND_EMAIL_NULL);
        }
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>().eq(User::getEmail, email);
        User one = this.getOne(lqw);
        if (one != null) {
            throw new BindEmailException(MessageConstant.BIND_EMAIL_EXIST);
        }
        //获取存储的验证码
        String code = (String) redisTemplate.opsForValue().get(email);
        if (code == null || !(code.equalsIgnoreCase(userLoginDto.getCaptcha()))) {
            throw new CaptchaException(MessageConstant.CAPTCHA_ERROR);
        }
        User user = new User();
        user.setEmail(userLoginDto.getEmail());
        LambdaUpdateWrapper<User> lqwUser = new LambdaUpdateWrapper<>();
        lqwUser.eq(User::getId, BaseContext.getCurrentId()).set(User::getEmail, email);
        int update = userMapper.update(lqwUser);
        if (update != 1) {
            throw new BindEmailException(MessageConstant.BIND_EMAIL_ERROR);
        }
        redisTemplate.delete(email);
    }

    /**
     * 修改用户信息
     *
     * @param userDTO
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateUser(UserDTO userDTO) {
        User user = new User();
        BeanUtils.copyProperties(userDTO, user);
        return this.updateById(user);
    }

    /**
     * 签到
     *
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String signIn() {
        int userId = BaseContext.getCurrentId();
        String userKey = "user:" + userId;
        String lockKey = LOCK_PREFIX + userId;
        try {
            // 尝试获取锁
            Boolean lockAcquired = redisTemplate.opsForValue().setIfAbsent(lockKey, "locked", LOCK_EXPIRE_TIME, TimeUnit.SECONDS);
            if (Boolean.TRUE.equals(lockAcquired)) {
                // 锁获取成功
                if (Boolean.TRUE.equals(redisTemplate.hasKey(userKey))) {
                    Map<Object, Object> entries = redisTemplate.opsForHash().entries(userKey);
                    if ("0".equals(entries.get("status"))) {
                        redisTemplate.opsForHash().put(userKey, "status", "1");
                        int day = Integer.parseInt((String) entries.get("dayNumber")) + 1;
                        int s = INITIAL_CREDITS;
                        if (day >= 7 && day < 15) {
                            s = (int) (s * day * 1.5);
                        } else if (day >= 15) {
                            s = s * day * 2;
                        } else {
                            s = s * day;
                        }
                        User user = userMapper.selectById(userId);
                        user.setPoints(user.getPoints() + s);
                        userMapper.updateById(user);
                        integralService.save(Integral.builder()
                                .type(InitialType.SIGN_TYPE.getType())
                                .userId(userId)
                                .number(s)
                                .tittle("签到积分")
                                .createTime(LocalDateTime.now())
                                .build());
                        redisTemplate.opsForHash().put(userKey, "dayNumber", String.valueOf(day));
                        return MessageConstant.SUCCESS_MESSAGE;
                    } else {
                        return MessageConstant.FAILURE_MESSAGE;
                    }
                } else {
                    // 用户本月未签到，执行初始化操作
                    boolean save = integralService.save(Integral.builder()
                            .type(InitialType.SIGN_TYPE.getType())
                            .userId(userId)
                            .number(INITIAL_CREDITS)
                            .tittle("签到积分")
                            .build());
                    if (save) {
                        HashMap<String, Object> valueMap = new HashMap<>();
                        valueMap.put("status", "1");
                        valueMap.put("dayNumber", "1");
                        redisTemplate.opsForHash().putAll(userKey, valueMap);
                        User user = userMapper.selectById(userId);
                        user.setPoints(user.getPoints() + INITIAL_CREDITS);
                        userMapper.updateById(user);
                        return MessageConstant.SUCCESS_MESSAGE;
                    }
                }
            } else {
                // 获取锁失败，说明正在被其他线程使用
                return MessageConstant.MESSAGE_TOO_MANY_REQUESTS; // 可以自定义返回信息
            }
        } finally {
            // 释放锁
            redisTemplate.delete(lockKey);
        }
        return MessageConstant.FAILURE_MESSAGE;
    }

    /**
     *
     */



}
